package phong.musicplayer;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import models.Song;
import models.SongData;
import phong.musicplayer.PlayService.ServiceBinder;
import views.SongAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.IBinder;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnSeekBarChangeListener {

	Button btnPlayPause, btnStop, btnNext, btnPrevious;
	Intent playServiceIntent;
	boolean boolMusicPlaying = false;
	boolean boolPause = false;
	boolean isOnline;

	BroadcastReceiver receiver;
	PlayService playService;

	boolean bufferBroadcastIsRegistered;
	ProgressDialog progressDialogBuffer = null;

	SeekBar seekBar;
	int seekMax, song_time;
	boolean seekBroadcastIsRegistered;
	Intent seekChangeByUserIntent;
	TextView song_length, song_title, current_song, current_singer;
	static TextView song_running_time;

	static String BROADCAST_SEEKBAR = "phong.musicplayer.sendseekbar";

	ListView listView;
	SongAdapter songAdapter;

	int currentSongIndex = 0;
	Handler handler;

	ProgressDialog progressDialogDownload;
	String fileName;

	@Override
	protected void onStart() {
		super.onStart();
		LocalBroadcastManager.getInstance(this).registerReceiver((receiver),
				new IntentFilter(PlayService.PLAY_COMPLETED));
	}

	@Override
	protected void onStop() {
		super.onStop();
		LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		handler = new Handler(new Callback() {
			@Override
			public boolean handleMessage(Message msg) {
				if (msg.what == SongData.LOAD_COMPLETED) {
					listView = (ListView) findViewById(R.id.listView1);
					songAdapter = new SongAdapter(MainActivity.this,
							R.layout.layout_list_item, SongData.getSongData(),
							handler);
					listView.setAdapter(songAdapter);
					listView.setOnItemClickListener(new OnItemClickListener() {
						@Override
						public void onItemClick(AdapterView<?> arg0, View v,
								int pos, long id) {
							btnPlayPause
									.setBackgroundResource(R.drawable.pause);
							boolMusicPlaying = true;
							play(SongData.getSongData().get(pos));
							currentSongIndex = pos;
						}
					});
				} else if (msg.what == SongAdapter.ON_CLICK_DOWNLOAD) {
					Bundle bundle = msg.getData();
					String urlDownload = bundle.getString("song");
					Log.d("test", "URL : " + urlDownload);

					fileName = urlDownload.substring(
							urlDownload.lastIndexOf("/") + 1,
							urlDownload.length());

					Log.d("test", "File Name : " + fileName);

					downloadMusic(urlDownload);

				}
				return false;
			}
		});
		SongData.init(handler, this);
		SongData.getSongData();

		receiver = new BroadcastReceiver() {

			@Override
			public void onReceive(Context context, Intent intent) {
				String sPlayCompleted = intent
						.getStringExtra(PlayService.PLAY_COMPLETED);
				String sPlaying = intent.getStringExtra(PlayService.PLAYING);

				if (sPlayCompleted.equalsIgnoreCase(PlayService.PLAY_COMPLETED)) {
					Log.d("test", "PLAY_COMPLETED");
					int length = SongData.getSongData().size();
					if (currentSongIndex < length - 1) {
						currentSongIndex++;
					} else {
						currentSongIndex = 0;
					}
					play(SongData.getSongData().get(currentSongIndex));
				} else if (sPlaying.equalsIgnoreCase(PlayService.PLAYING)) {
					btnPlayPause.setBackgroundResource(R.drawable.pause);
				}
			}
		};

		try {
			playServiceIntent = new Intent(this, PlayService.class);

			// Set up seekbar intent for broadcasting new position to service
			seekChangeByUserIntent = new Intent(BROADCAST_SEEKBAR);

			initView();
			setListener();
		} catch (Exception e) {
			e.printStackTrace();
			Log.d("test", "test");
			Toast.makeText(getApplicationContext(),
					e.getClass().getName() + " " + e.getMessage(),
					Toast.LENGTH_LONG).show();
		}
	}

	void play(Song song) {
		stopPlayService();

		// play music
		playServiceIntent.putExtra("sentAudioLink", song.getUrlDownload());
		startService(playServiceIntent);
		bindService(playServiceIntent, conn, BIND_AUTO_CREATE);
		btnPlayPause.setBackgroundResource(R.drawable.pause);
		boolMusicPlaying = true;
		boolPause = false;

		// Register receiver for seekbar
		registerReceiver(seekBroadcastReceiver, new IntentFilter(
				PlayService.BROADCAST_SEEK));
		seekBroadcastIsRegistered = true;
	}

	void initView() {
		btnPlayPause = (Button) findViewById(R.id.btnPlayPause);
		// btnPlayPause.setBackgroundResource(R.drawable.play);
		btnStop = (Button) findViewById(R.id.btnStop);
		btnNext = (Button) findViewById(R.id.btnNext);
		btnPrevious = (Button) findViewById(R.id.btnPrevious);

		seekBar = (SeekBar) findViewById(R.id.seekBar);
		song_length = (TextView) findViewById(R.id.song_length);
		song_running_time = (TextView) findViewById(R.id.song_running_time);
		song_title = (TextView) findViewById(R.id.song_title);
		current_song = (TextView) findViewById(R.id.current_song);
		current_singer = (TextView) findViewById(R.id.current_singer);
	}

	void setListener() {
		btnPlayPause.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				btnPlayPauseClick();
			}
		});

		btnStop.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (boolMusicPlaying || boolPause) {
					// stopPlayService();
					playService.cancelNotification();
					playService.mediaPlayer.stop();
					seekBar.setProgress(0);
					song_running_time.setText("00:00:00");

					btnPlayPause.setBackgroundResource(R.drawable.play);
					boolMusicPlaying = false;
					boolPause = false;
				}
			}
		});

		btnNext.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				int length = SongData.getSongData().size();
				if (currentSongIndex < length - 1) {
					currentSongIndex++;
					play(SongData.getSongData().get(currentSongIndex));
				} else {
					currentSongIndex = 0;
					play(SongData.getSongData().get(currentSongIndex));
				}
			}
		});

		btnPrevious.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				int length = SongData.getSongData().size();
				if (currentSongIndex > 0) {
					currentSongIndex--;
					play(SongData.getSongData().get(currentSongIndex));
				} else {
					currentSongIndex = length - 1;
					play(SongData.getSongData().get(currentSongIndex));
				}
			}
		});

		seekBar.setOnSeekBarChangeListener(this);
	}

	void btnPlayPauseClick() {

		checkConnectivity();
		if (isOnline) {

			// play music at the first time
			if (!boolMusicPlaying && !boolPause) {
				stopPlayService();

				// get current song download url.
				String currentSongUrl = SongData.getSongData()
						.get(currentSongIndex).getUrlDownload();

				// play music
				playServiceIntent.putExtra("sentAudioLink", currentSongUrl);
				startService(playServiceIntent);
				bindService(playServiceIntent, conn, BIND_AUTO_CREATE);

				btnPlayPause.setBackgroundResource(R.drawable.pause);
				boolMusicPlaying = true;
			}

			// resume music
			else if (!boolMusicPlaying && boolPause) {
				playService.resume();

				btnPlayPause.setBackgroundResource(R.drawable.pause);
				boolMusicPlaying = true;
				boolPause = false;
			}

			// pause music
			else {
				playService.pause();
				btnPlayPause.setBackgroundResource(R.drawable.play);
				boolPause = true;
				boolMusicPlaying = false;
			}

			// Register receiver for seekbar
			registerReceiver(seekBroadcastReceiver, new IntentFilter(
					PlayService.BROADCAST_SEEK));
			seekBroadcastIsRegistered = true;

		} else {
			AlertDialog alertDialog = new AlertDialog.Builder(this).create();
			alertDialog.setTitle("Network Not Connected...");
			alertDialog.setMessage("Please connect to a network and try again");
			alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							if (which == -1)
								dialog.cancel();
						}
					});
			alertDialog.setIcon(R.drawable.network_error);
			btnPlayPause.setBackgroundResource(R.drawable.play);
			alertDialog.show();
		}

	}

	void stopPlayService() {

		// Unregister seekbar broadcast receiver
		if (seekBroadcastIsRegistered) {
			try {
				unregisterReceiver(seekBroadcastReceiver);
				seekBroadcastIsRegistered = false;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		try {
			stopService(playServiceIntent);
		} catch (Exception e) {
			e.printStackTrace();

			Log.d("test 1", "test 1");
			Toast.makeText(getApplicationContext(),
					e.getClass().getName() + " " + e.getMessage(),
					Toast.LENGTH_LONG).show();
		}
		boolMusicPlaying = false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	ServiceConnection conn = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {

			PlayService.ServiceBinder binder = (ServiceBinder) (service);
			playService = binder.getService();
		}
	};

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			moveTaskToBack(true);
			return true;
		}
		return super.onKeyDown(keyCode, event);
	};

	void checkConnectivity() {
		ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
				.isConnectedOrConnecting()
				|| connectivityManager.getNetworkInfo(
						ConnectivityManager.TYPE_WIFI)
						.isConnectedOrConnecting()) {
			isOnline = true;
		} else {
			isOnline = false;
		}
	}

	// ------------ Buffer progress dialog---------------------------------
	BroadcastReceiver bufferBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent bufferIntent) {
			showProgressDialog(bufferIntent);
		}
	};

	void showProgressDialog(Intent bufferIntent) {
		String bufferValue = bufferIntent.getStringExtra("buffering");
		int bufferIntValue = Integer.parseInt(bufferValue);
		switch (bufferIntValue) {
		case 0: // buffer complete
			if (progressDialogBuffer != null) {
				progressDialogBuffer.dismiss();
			}
			break;
		case 1: // buffering
			checkConnectivity();
			if (isOnline)
				bufferDialog();
			else {
				try {
					unregisterReceiver(bufferBroadcastReceiver);
					bufferBroadcastIsRegistered = false;
				} catch (Exception e) {
					e.printStackTrace();
				}
				playService.cancelNotification();
				
				AlertDialog alertDialog = new AlertDialog.Builder(this)
						.create();
				alertDialog.setTitle("Error");
				alertDialog.setMessage("Can't Connect To Server");
				alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								if (which == -1)
									dialog.cancel();
							}
						});
				alertDialog.setIcon(R.drawable.network_error);
				alertDialog.show();
				
			}
			break;
		case -1: // music link error cant play & progress dialog cant exit
			if (progressDialogBuffer != null) {
				progressDialogBuffer.dismiss();
			}
			break;
		}
	}

	void bufferDialog() {
		progressDialogBuffer = ProgressDialog.show(MainActivity.this,
				"Buffering...", "Acquiring Song...", true);
		progressDialogBuffer.setIndeterminate(true);
		progressDialogBuffer.setCancelable(true);
	}

	// ---------- End code buffer progress dialog-----------------------------

	@Override
	protected void onPause() {

		// Unregister buffer broadcast receiver
		if (bufferBroadcastIsRegistered) {
			try {
				unregisterReceiver(bufferBroadcastReceiver);
				bufferBroadcastIsRegistered = false;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// Unregister seekbar broadcast receiver
		if (seekBroadcastIsRegistered) {
			try {
				unregisterReceiver(seekBroadcastReceiver);
				seekBroadcastIsRegistered = false;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		super.onPause();
	}

	@Override
	protected void onResume() {

		// Register buffer broadcast receiver
		if (!bufferBroadcastIsRegistered) {
			try {
				registerReceiver(bufferBroadcastReceiver, new IntentFilter(
						PlayService.BROADCAST_BUFFER));
				bufferBroadcastIsRegistered = true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// Register seekbar broadcast receiver
		if (!seekBroadcastIsRegistered) {
			try {
				registerReceiver(seekBroadcastReceiver, new IntentFilter(
						PlayService.BROADCAST_SEEK));
				seekBroadcastIsRegistered = true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		super.onResume();
	}

	// Updating position of seekbar from service
	BroadcastReceiver seekBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent serviceIntent) {
			updateUI(serviceIntent);
		}
	};

	void updateUI(Intent serviceIntent) {
		String media_max = serviceIntent.getStringExtra("media_max");
		seekMax = Integer.parseInt(media_max);
		seekBar.setMax(seekMax);
		song_length.setText(getDurationString(seekMax));

		String counter = serviceIntent.getStringExtra("counter");
		int seekProgress = Integer.parseInt(counter);
		seekBar.setProgress(seekProgress);

		song_time = Integer.parseInt(counter);
		song_running_time.setText(getDurationString(song_time));

		current_song.setVisibility(View.VISIBLE);
		current_song.setText(SongData.getSongData().get(currentSongIndex)
				.getSongTitle().toString());
		current_singer.setVisibility(View.VISIBLE);
		current_singer.setText(SongData.getSongData().get(currentSongIndex)
				.getSinger().toString());

		Log.d("test", "seekProgress : " + seekProgress + " -- seekMax : "
				+ seekMax);
	}

	String getDurationString(int milliseconds) {
		int seconds = milliseconds / 1000;
		int hours = seconds / 3600;
		int minutes = (seconds % 3600) / 60;
		seconds = seconds % 60;

		return twoDigitString(hours) + ":" + twoDigitString(minutes) + ":"
				+ twoDigitString(seconds);
	}

	String twoDigitString(int number) {
		if (number == 0) {
			return "00";
		}
		if (number / 10 == 0) {
			return "0" + number;
		}
		return String.valueOf(number);
	}

	// When user manually moves seekbar, broadcast new position to service
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if (fromUser) {
			int seekPos = seekBar.getProgress();
			seekChangeByUserIntent.putExtra("seekpos", seekPos);
			sendBroadcast(seekChangeByUserIntent);
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

	public void downloadMusic(String url) {
		progressDialogDownload = new ProgressDialog(MainActivity.this);
		progressDialogDownload.setMessage("Downloading...");
		progressDialogDownload.setIndeterminate(true);
		progressDialogDownload
				.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		progressDialogDownload.setCancelable(true);

		// execute this when the downloader must be fired
		final DownloadTask downloadTask = new DownloadTask(MainActivity.this);
		downloadTask.execute(url);

		progressDialogDownload
				.setOnCancelListener(new DialogInterface.OnCancelListener() {
					@Override
					public void onCancel(DialogInterface dialog) {
						downloadTask.cancel(true);
					}
				});
	}

	public class DownloadTask extends AsyncTask<String, Integer, String> {

		private Context context;

		public DownloadTask(Context context) {
			this.context = context;
		}

		@Override
		protected String doInBackground(String... sUrl) {
			// take CPU lock to prevent CPU from going off if the user
			// presses the power button during download
			// PowerManager pm = (PowerManager) context
			// .getSystemService(Context.POWER_SERVICE);
			// PowerManager.WakeLock wl = pm.newWakeLock(
			// PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
			// wl.acquire();

			try {
				InputStream input = null;
				OutputStream output = null;
				HttpURLConnection connection = null;
				try {
					URL url = new URL(sUrl[0]);
					connection = (HttpURLConnection) url.openConnection();
					connection.connect();

					// expect HTTP 200 OK, so we don't mistakenly save error
					// report
					// instead of the file
					if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
						return "Server returned HTTP "
								+ connection.getResponseCode() + " "
								+ connection.getResponseMessage();

					// this will be useful to display download percentage
					// might be -1: server did not report the length
					int fileLength = connection.getContentLength();

					// download the file
					input = connection.getInputStream();
					output = new FileOutputStream(Environment
							.getExternalStorageDirectory().getPath()
							+ "/"
							+ fileName);

					byte data[] = new byte[4096];
					long total = 0;
					int count;
					while ((count = input.read(data)) != -1) {
						// allow canceling with back button
						if (isCancelled()) {
							cancel(true);
							// return null;
						}
						total += count;
						// publishing the progress....
						if (fileLength > 0) // only if total length is known
							publishProgress((int) (total * 100 / fileLength));
						output.write(data, 0, count);
					}
				} catch (Exception e) {
					return e.toString();
				} finally {
					try {
						if (output != null)
							output.close();
						if (input != null)
							input.close();
					} catch (IOException ignored) {
					}

					if (connection != null)
						connection.disconnect();
				}
			} finally {
				// wl.release();
			}
			return null;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			progressDialogDownload.show();
		}

		@Override
		protected void onProgressUpdate(Integer... progress) {
			super.onProgressUpdate(progress);
			// if we get here, length is known, now set indeterminate to false
			progressDialogDownload.setIndeterminate(false);
			progressDialogDownload.setMax(100);
			progressDialogDownload.setProgress(progress[0]);
		}

		@Override
		protected void onPostExecute(String result) {
			progressDialogDownload.dismiss();
			if (result != null)
				Toast.makeText(context, "Download error : " + result,
						Toast.LENGTH_LONG).show();
			else
				Toast.makeText(context, "File downloaded", Toast.LENGTH_SHORT)
						.show();
		}
	}
}
